<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Kernel API</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d0/d1e/gapi.html">Graph API</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Kernel API </div>  </div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>Table of Contents</h3>
<ul><li class="level1"><a href="#gapi_defining_kernel">Defining a kernel</a></li>
<li class="level1"><a href="#gapi_kernel_supp_info">Extra information</a></li>
<li class="level1"><a href="#gapi_kernel_implementing">Implementing a kernel</a></li>
<li class="level1"><a href="#gapi_kernel_compound">Compound kernels</a></li>
</ul>
</div>
<div class="textblock"><h1>G-API Kernel API</h1>
<p>The core idea behind G-API is portability &ndash; a pipeline built with G-API must be portable (or at least able to be portable). It means that either it works out-of-the box when compiled for new platform, <em>or</em> G-API provides necessary tools to make it running there, with little-to-no changes in the algorithm itself.</p>
<p>This idea can be achieved by separating kernel interface from its implementation. Once a pipeline is built using kernel interfaces, it becomes implementation-neutral &ndash; the implementation details (i.e. which kernels to use) are passed on a separate stage (graph compilation).</p>
<p>Kernel-implementation hierarchy may look like:</p>
<div class="dotgraph">
<iframe scrolling="no" frameborder="0" src="../../dot_inline_dotgraph_1.svg" width="790" height="160"><p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p></iframe><div class="caption">
Kernel API/implementation hierarchy example</div>
</div>
<p>A pipeline itself then can be expressed only in terms of <code>A</code>, <code>B</code>, and so on, and choosing which implementation to use in execution becomes an external parameter.</p>
<h1><a class="anchor" id="gapi_defining_kernel"></a>
Defining a kernel</h1>
<p>G-API provides a macro to define a new kernel interface &ndash; <a class="el" href="../../de/d7f/gkernel_8hpp.html#a83d2e73c619a545f69e89bf7b03cbd80">G_TYPED_KERNEL()</a>:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &lt;<a class="code" href="../../d7/d20/gapi_8hpp.html">opencv2/gapi.hpp</a>&gt;</span></div><div class="line"></div><div class="line"><a class="code" href="../../de/d7f/gkernel_8hpp.html#a83d2e73c619a545f69e89bf7b03cbd80">G_TYPED_KERNEL</a>(GFilter2D,</div><div class="line">               &lt;<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>(<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>,<span class="keywordtype">int</span>,<a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a>,<a class="code" href="../../db/d4e/classcv_1_1Point__.html">cv::Point</a>,<span class="keywordtype">double</span>,<span class="keywordtype">int</span>,<a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">cv::Scalar</a>)&gt;,</div><div class="line">               <span class="stringliteral">&quot;org.opencv.imgproc.filters.filter2D&quot;</span>)</div><div class="line">{</div><div class="line">    <span class="keyword">static</span> <a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a>                 <span class="comment">// outMeta&#39;s return value type</span></div><div class="line">    outMeta(<a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a>    in       ,  <span class="comment">// descriptor of input GMat</span></div><div class="line">            <span class="keywordtype">int</span>             ddepth   ,  <span class="comment">// depth parameter</span></div><div class="line">            <a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a>      <span class="comment">/* coeffs */</span>,  <span class="comment">// (unused)</span></div><div class="line">            <a class="code" href="../../db/d4e/classcv_1_1Point__.html">cv::Point</a>    <span class="comment">/* anchor */</span>,  <span class="comment">// (unused)</span></div><div class="line">            <span class="keywordtype">double</span>       <span class="comment">/* scale  */</span>,  <span class="comment">// (unused)</span></div><div class="line">            <span class="keywordtype">int</span>          <span class="comment">/* border */</span>,  <span class="comment">// (unused)</span></div><div class="line">            <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">cv::Scalar</a>   <span class="comment">/* bvalue */</span> ) <span class="comment">// (unused)</span></div><div class="line">    {</div><div class="line">        <span class="keywordflow">return</span> in.<a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html#a82c512d99a4ed51a3372b78a9ddc8dce">withDepth</a>(ddepth);</div><div class="line">    }</div><div class="line">};</div></div><!-- fragment --><p> This macro is a shortcut to a new type definition. It takes three arguments to register a new type, and requires type body to be present (see <a class="el" href="../../d0/d25/gapi_kernel_api.html#gapi_kernel_supp_info">below</a>). The macro arguments are:</p><ol type="1">
<li>Kernel interface name &ndash; also serves as a name of new type defined with this macro;</li>
<li>Kernel signature &ndash; an <code>std::function&lt;&gt;</code>-like signature which defines API of the kernel;</li>
<li>Kernel's unique name &ndash; used to identify kernel when its type informattion is stripped within the system.</li>
</ol>
<p>Kernel declaration may be seen as function declaration &ndash; in both cases a new entity must be used then according to the way it was defined.</p>
<p>Kernel signature defines kernel's usage syntax &ndash; which parameters it takes during graph construction. Implementations can also use this signature to derive it into backend-specific callback signatures (see next chapter).</p>
<p>Kernel may accept values of any type, and G-API <em>dynamic</em> types are handled in a special way. All other types are opaque to G-API and passed to kernel in <code>outMeta()</code> or in execution callbacks as-is.</p>
<p>Kernel's return value can <em>only</em> be of G-API dynamic type &ndash; <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>, <a class="el" href="../../d9/d98/classcv_1_1GScalar.html">cv::GScalar</a>, or <code><a class="el" href="../../d3/d44/classcv_1_1GArray.html">cv::GArray</a>&lt;T&gt;</code>. If an operation has more than one output, it should be wrapped into an <code>std::tuple&lt;&gt;</code> (which can contain only mentioned G-API types). Arbitrary-output-number operations are not supported.</p>
<p>Once a kernel is defined, it can be used in pipelines with special, G-API-supplied method "::on()". This method has the same signature as defined in kernel, so this code:</p>
<div class="fragment"><div class="line"><a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> in;</div><div class="line"><a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> out = GFilter2D::on(<span class="comment">/* GMat    */</span>  in,</div><div class="line">                             <span class="comment">/* int     */</span>  -1,</div><div class="line">                             <span class="comment">/* Mat     */</span>  conv_kernel_mat,</div><div class="line">                             <span class="comment">/* Point   */</span>  <a class="code" href="../../db/d4e/classcv_1_1Point__.html">cv::Point</a>(-1,-1),</div><div class="line">                             <span class="comment">/* double  */</span>  0.,</div><div class="line">                             <span class="comment">/* int     */</span>  <a class="code" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5afe14c13a4ea8b8e3b3ef399013dbae01">cv::BORDER_DEFAULT</a>,</div><div class="line">                             <span class="comment">/* Scalar  */</span>  <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">cv::Scalar</a>(0));</div></div><!-- fragment --><p> is a perfectly legal construction. This example has some verbosity, though, so usually a kernel declaration comes with a C++ function wrapper ("factory method") which enables optional parameters, more compact syntax, Doxygen comments, etc:</p>
<div class="fragment"><div class="line"><a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> <a class="code" href="../../d5/df1/group__imgproc__hal__functions.html#ga42c2468ab3a1238fbf48458c57169081">filter2D</a>(<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>   in,</div><div class="line">                  <span class="keywordtype">int</span>        ddepth,</div><div class="line">                  <a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a>    k,</div><div class="line">                  <a class="code" href="../../db/d4e/classcv_1_1Point__.html">cv::Point</a>  anchor  = <a class="code" href="../../db/d4e/classcv_1_1Point__.html">cv::Point</a>(-1,-1),</div><div class="line">                  <span class="keywordtype">double</span>     <a class="code" href="../../d6/d84/namespacecv_1_1quality_1_1quality__utils.html#ae55d1c89ff5761730174745401162743">scale</a>   = 0.,</div><div class="line">                  <span class="keywordtype">int</span>        border  = <a class="code" href="../../d2/de8/group__core__array.html#gga209f2f4869e304c82d07739337eae7c5afe14c13a4ea8b8e3b3ef399013dbae01">cv::BORDER_DEFAULT</a>,</div><div class="line">                  <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">cv::Scalar</a> bval    = <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">cv::Scalar</a>(0))</div><div class="line">{</div><div class="line">    <span class="keywordflow">return</span> GFilter2D::on(in, ddepth, k, anchor, <a class="code" href="../../d6/d84/namespacecv_1_1quality_1_1quality__utils.html#ae55d1c89ff5761730174745401162743">scale</a>, border, bval);</div><div class="line">}</div></div><!-- fragment --><p> so now it can be used like:</p>
<div class="fragment"><div class="line"><a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> in;</div><div class="line"><a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> out = <a class="code" href="../../d5/df1/group__imgproc__hal__functions.html#ga42c2468ab3a1238fbf48458c57169081">filter2D</a>(in, -1, conv_kernel_mat);</div></div><!-- fragment --> <h1><a class="anchor" id="gapi_kernel_supp_info"></a>
Extra information</h1>
<p>In the current version, kernel declaration body (everything within the curly braces) must contain a static function <code>outMeta()</code>. This function establishes a functional dependency between operation's input and output metadata.</p>
<p><em>Metadata</em> is an information about data kernel operates on. Since non-G-API types are opaque to G-API, G-API cares only about <code>G*</code> data descriptors (i.e. dimensions and format of <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>, etc).</p>
<p><code>outMeta()</code> is also an example of how kernel's signature can be transformed into a derived callback &ndash; note that in this example, <code>outMeta()</code> signature exactly follows the kernel signature (defined within the macro) but is different &ndash; where kernel expects <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>, <code>outMeta()</code> takes and returns <a class="el" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a> (a G-API structure metadata for <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>).</p>
<p>The point of <code>outMeta()</code> is to propagate metadata information within computation from inputs to outputs and infer metadata of internal (intermediate, temporary) data objects. This information is required for further pipeline optimizations, memory allocation, and other operations done by G-API framework during graph compilation.</p>
<h1><a class="anchor" id="gapi_kernel_implementing"></a>
Implementing a kernel</h1>
<p>Once a kernel is declared, its interface can be used to implement versions of this kernel in different backends. This concept is naturally projected from object-oriented programming "Interface/Implementation" idiom: an interface can be implemented multiple times, and different implementations of a kernel should be substitutable with each other without breaking the algorithm (pipeline) logic (Liskov Substitution Principle).</p>
<p>Every backend defines its own way to implement a kernel interface. This way is regular, though &ndash; whatever plugin is, its kernel implementation must be "derived" from a kernel interface type.</p>
<p>Kernel implementation are then organized into <em>kernel packages</em>. Kernel packages are passed to <a class="el" href="../../d9/dfe/classcv_1_1GComputation.html#ab11bcc0578f9aa5ec8f8eaf6cda0dfa8" title="Compile the computation for specific input format(s). ">cv::GComputation::compile()</a> as compile arguments, with some hints to G-API on how to select proper kernels (see more on this in "Heterogeneity"[TBD]).</p>
<p>For example, the aforementioned <code>Filter2D</code> is implemented in "reference" CPU (OpenCV) plugin this way (<em>NOTE</em> &ndash; this is a simplified form with improper border handling):</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &lt;<a class="code" href="../../da/d73/gcpukernel_8hpp.html">opencv2/gapi/cpu/gcpukernel.hpp</a>&gt;</span>     <span class="comment">// GAPI_OCV_KERNEL()</span></div><div class="line"><span class="preprocessor">#include &lt;<a class="code" href="../../d1/d4f/imgproc_2include_2opencv2_2imgproc_8hpp.html">opencv2/imgproc.hpp</a>&gt;</span>                 <span class="comment">// cv::filter2D()</span></div><div class="line"></div><div class="line"><a class="code" href="../../da/d73/gcpukernel_8hpp.html#aacef2b3c16c285adbd70a03ae8aedc46">GAPI_OCV_KERNEL</a>(GCPUFilter2D, GFilter2D)</div><div class="line">{</div><div class="line">    <span class="keyword">static</span> <span class="keywordtype">void</span></div><div class="line">    run(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a>    &amp;in,       <span class="comment">// in - derived from GMat</span></div><div class="line">        <span class="keyword">const</span> <span class="keywordtype">int</span>         ddepth,   <span class="comment">// opaque (passed as-is)</span></div><div class="line">        <span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a>    &amp;k,        <span class="comment">// opaque (passed as-is)</span></div><div class="line">        <span class="keyword">const</span> <a class="code" href="../../db/d4e/classcv_1_1Point__.html">cv::Point</a>  &amp;anchor,   <span class="comment">// opaque (passed as-is)</span></div><div class="line">        <span class="keyword">const</span> <span class="keywordtype">double</span>      delta,    <span class="comment">// opaque (passed as-is)</span></div><div class="line">        <span class="keyword">const</span> <span class="keywordtype">int</span>         border,   <span class="comment">// opaque (passed as-is)</span></div><div class="line">        <span class="keyword">const</span> <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">cv::Scalar</a> &amp;,         <span class="comment">// opaque (passed as-is)</span></div><div class="line">        <a class="code" href="../../d3/d63/classcv_1_1Mat.html">cv::Mat</a>          &amp;out)      <span class="comment">// out - derived from GMat (retval)</span></div><div class="line">    {</div><div class="line">        <a class="code" href="../../d4/d86/group__imgproc__filter.html#ga27c049795ce870216ddfb366086b5a04">cv::filter2D</a>(in, out, ddepth, k, anchor, delta, border);</div><div class="line">    }</div><div class="line">};</div></div><!-- fragment --><p> Note how CPU (OpenCV) plugin has transformed the original kernel signature:</p><ul>
<li>Input <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> has been substituted with <a class="el" href="../../d3/d63/classcv_1_1Mat.html" title="n-dimensional dense array class ">cv::Mat</a>, holding actual input data for the underlying OpenCV function call;</li>
<li>Output <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> has been transformed into extra output parameter, thus <code>GCPUFilter2D::run()</code> takes one argument more than the original kernel signature.</li>
</ul>
<p>The basic intuition for kernel developer here is <em>not to care</em> where that <a class="el" href="../../d3/d63/classcv_1_1Mat.html" title="n-dimensional dense array class ">cv::Mat</a> objects come from instead of the original <a class="el" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> &ndash; and just follow the signature conventions defined by the plugin. G-API will call this method during execution and supply all the necessary information (and forward the original opaque data as-is).</p>
<h1><a class="anchor" id="gapi_kernel_compound"></a>
Compound kernels</h1>
<p>Sometimes kernel is a single thing only on API level. It is convenient for users, but on a particular implementation side it would be better to have multiple kernels (a subgraph) doing the thing instead. An example is <a class="el" href="../../dd/d1a/group__imgproc__feature.html#ga1d6bb77486c8f92d79c8793ad995d541" title="Determines strong corners on an image. ">goodFeaturesToTrack()</a> &ndash; while in OpenCV backend it may remain a single kernel, with Fluid it becomes compound &ndash; Fluid can handle Harris response calculation but can't do sparse non-maxima suppression and point extraction to an STL vector:</p>
<p>A compound kernel <em>implementation</em> can be defined using a generic macro <a class="el" href="../../da/dc1/gcompoundkernel_8hpp.html#ad55e42d2657e9063c4888f109cdff78f">GAPI_COMPOUND_KERNEL()</a>:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &lt;<a class="code" href="../../da/dc1/gcompoundkernel_8hpp.html">opencv2/gapi/gcompoundkernel.hpp</a>&gt;</span>       <span class="comment">// GAPI_COMPOUND_KERNEL()</span></div><div class="line"></div><div class="line"><span class="keyword">using</span> PointArray2f = <a class="code" href="../../d3/d44/classcv_1_1GArray.html">cv::GArray&lt;cv::Point2f&gt;</a>;</div><div class="line"></div><div class="line"><a class="code" href="../../de/d7f/gkernel_8hpp.html#a83d2e73c619a545f69e89bf7b03cbd80">G_TYPED_KERNEL</a>(HarrisCorners,</div><div class="line">               &lt;PointArray2f(<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>,<span class="keywordtype">int</span>,<span class="keywordtype">double</span>,<span class="keywordtype">double</span>,<span class="keywordtype">int</span>,<span class="keywordtype">double</span>)&gt;,</div><div class="line">               <span class="stringliteral">&quot;org.opencv.imgproc.harris_corner&quot;</span>)</div><div class="line">{</div><div class="line">    <span class="keyword">static</span> <a class="code" href="../../d7/dd5/structcv_1_1GArrayDesc.html">cv::GArrayDesc</a> outMeta(<span class="keyword">const</span> <a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a> &amp;,</div><div class="line">                                  <span class="keywordtype">int</span>,</div><div class="line">                                  <span class="keywordtype">double</span>,</div><div class="line">                                  <span class="keywordtype">double</span>,</div><div class="line">                                  <span class="keywordtype">int</span>,</div><div class="line">                                  <span class="keywordtype">double</span>)</div><div class="line">    {</div><div class="line">        <span class="comment">// No special metadata for arrays in G-API (yet)</span></div><div class="line">        <span class="keywordflow">return</span> <a class="code" href="../../d3/d0c/group__gapi__meta__args.html#ga71b2cb69162686ddd6ada83c75d4b44e">cv::empty_array_desc</a>();</div><div class="line">    }</div><div class="line">};</div><div class="line"></div><div class="line"><span class="comment">// Define Fluid-backend-local kernels which form GoodFeatures</span></div><div class="line"><a class="code" href="../../de/d7f/gkernel_8hpp.html#a83d2e73c619a545f69e89bf7b03cbd80">G_TYPED_KERNEL</a>(HarrisResponse,</div><div class="line">               &lt;<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>(<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>,<span class="keywordtype">double</span>,<span class="keywordtype">int</span>,<span class="keywordtype">double</span>)&gt;,</div><div class="line">               <span class="stringliteral">&quot;org.opencv.fluid.harris_response&quot;</span>)</div><div class="line">{</div><div class="line">    <span class="keyword">static</span> <a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a> outMeta(<span class="keyword">const</span> <a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a> &amp;in,</div><div class="line">                                <span class="keywordtype">double</span>,</div><div class="line">                                <span class="keywordtype">int</span>,</div><div class="line">                                <span class="keywordtype">double</span>)</div><div class="line">    {</div><div class="line">        <span class="keywordflow">return</span> in.<a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html#a757aa00ebfaab7bc18a089bacef9bd28">withType</a>(<a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, 1);</div><div class="line">    }</div><div class="line">};</div><div class="line"></div><div class="line"><a class="code" href="../../de/d7f/gkernel_8hpp.html#a83d2e73c619a545f69e89bf7b03cbd80">G_TYPED_KERNEL</a>(ArrayNMS,</div><div class="line">               &lt;PointArray2f(<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a>,<span class="keywordtype">int</span>,<span class="keywordtype">double</span>)&gt;,</div><div class="line">               <span class="stringliteral">&quot;org.opencv.cpu.nms_array&quot;</span>)</div><div class="line">{</div><div class="line">    <span class="keyword">static</span> <a class="code" href="../../d7/dd5/structcv_1_1GArrayDesc.html">cv::GArrayDesc</a> outMeta(<span class="keyword">const</span> <a class="code" href="../../d0/d82/structcv_1_1GMatDesc.html">cv::GMatDesc</a> &amp;,</div><div class="line">                                  <span class="keywordtype">int</span>,</div><div class="line">                                  <span class="keywordtype">double</span>)</div><div class="line">    {</div><div class="line">        <span class="keywordflow">return</span> <a class="code" href="../../d3/d0c/group__gapi__meta__args.html#ga71b2cb69162686ddd6ada83c75d4b44e">cv::empty_array_desc</a>();</div><div class="line">    }</div><div class="line">};</div><div class="line"></div><div class="line"><a class="code" href="../../da/dc1/gcompoundkernel_8hpp.html#ad55e42d2657e9063c4888f109cdff78f">GAPI_COMPOUND_KERNEL</a>(GFluidHarrisCorners, HarrisCorners)</div><div class="line">{</div><div class="line">    <span class="keyword">static</span> PointArray2f</div><div class="line">    expand(<a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> in,</div><div class="line">           <span class="keywordtype">int</span>      maxCorners,</div><div class="line">           <span class="keywordtype">double</span>   quality,</div><div class="line">           <span class="keywordtype">double</span>   minDist,</div><div class="line">           <span class="keywordtype">int</span>      blockSize,</div><div class="line">           <span class="keywordtype">double</span>   k)</div><div class="line">    {</div><div class="line">        <a class="code" href="../../df/daa/classcv_1_1GMat.html">cv::GMat</a> response = HarrisResponse::on(in, quality, blockSize, k);</div><div class="line">        <span class="keywordflow">return</span> ArrayNMS::on(response, maxCorners, minDist);</div><div class="line">    }</div><div class="line">};</div><div class="line"></div><div class="line"><span class="comment">// Then implement HarrisResponse as Fluid kernel and NMSresponse</span></div><div class="line"><span class="comment">// as a generic (OpenCV) kernel</span></div></div><!-- fragment --><p>It is important to distinguish a compound kernel from G-API high-order function, i.e. a C++ function which looks like a kernel but in fact generates a subgraph. The core difference is that a compound kernel is an <em>implementation detail</em> and a kernel implementation may be either compound or not (depending on backend capabilities), while a high-order function is a "macro" in terms of G-API and so cannot act as an interface which then needs to be implemented by a backend. </p>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:34 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
